<?php


namespace app\common\service;

use think\Exception;

/**
 * Class RedisLimit
 * @package app\common\service
 * redis 简单限流
 */
class RedisLimit
{
    /**
     * @var int
     */
    static $oneITime = 60; // 单位时间 一分钟
    /**
     * @var int
     */
    static $oneIMax = 50; // 一个用户Ip一分钟最多仅允许访问访问10次

    /**
     * @var int
     */
    static $platITime = 60; // 针对所有用户，单位时间内允许访问的最大次数
    /**
     * @var int
     */
    static $platIMax = 10; // 针对所有的用户,该接口最多仅允许访问N次

    /**
     * Redis配置：IP
     */
    const REDIS_CONFIG_HOST = '127.0.0.1';
    /**
     * Redis配置：端口
     */
    const REDIS_CONFIG_PORT = 6379;


    /**
     * @return \think\response\Json
     * @throws Exception
     * 限制全局请求
     */
    public static function redis_lock_all_limit()
    {
        $redis = self::getRedisConn();
        //.... 针对平台全局锁，用于限制单位时间内所有用户访问的次数
        $platKey = md5(request()->url());

        $platFlowCount = $redis->get($platKey);// 平台访问次数
        if($platFlowCount){
            if($platFlowCount >= self::$platIMax){
                return json(['code'=>0,'msg'=>'超过访问次数']);
            }
        }
        $redis->incr($platKey);// ++1 次访问次数

        !$platFlowCount && $redis->expire($platKey,self::$platITime); // 设置锁的有效时间

        return json(['code'=>1,'msg'=>'通过']);

    }



    /**
     * @param $mer_no
     * @return \think\response\Json
     * @throws Exception
     * 限制单个商户在 多少秒内的请求次数
     */
    public static function redis_lock_single_limit($mer_no)
    {

        $redis = self::getRedisConn();
        // ... 针对单个商户户实现的访问锁
        $key = md5($mer_no.":".request()->ip());
        // 实现一个用户一分钟最多允许访问10次
        $userFlowCount = $redis->get($key); // 单个用户访问次数
        if($userFlowCount){
            if($userFlowCount >= self::$oneIMax){
                return json(['code'=>0,'msg'=>'超过访问次数']);
            }
        }
        $redis->incr($key);// ++1 次访问次数
        !$userFlowCount && $redis->expire($key,self::$oneITime);// 设置锁的有效时间
    }


    /**
     * @param string $strIp
     * @param int $intPort
     * @return \Redis
     * @throws Exception
     */
    public static function getRedisConn($strIp = self::REDIS_CONFIG_HOST, $intPort = self::REDIS_CONFIG_PORT)
    {
        try {
            if (!extension_loaded('redis')) {
                throw new \BadFunctionCallException('not support: redis');
            }
            $objRedis = new \Redis();
            $objRedis->connect($strIp, $intPort);
            return $objRedis;
        }catch (Exception $exception){
            throw new Exception($exception->getMessage());
        }
    }


}